package myCobra

import (
	"fmt"
	"os"
	"strings"

	flag "github.com/spf13/pflag"
)

var ()

type Command struct {
	Use string

	Short string
	Long  string
	Run   func(cmd *Command, args []string)

	commands []*Command
	choose   *Command
	parent   *Command

	args []string

	pflags *flag.FlagSet
}

func (c *Command) AddCommand(sub *Command) {
	for _, v := range c.commands {
		if v == sub {
			return
		}
	}
	c.commands = append(c.commands, sub)
	sub.parent = c
}

func (c *Command) Execute() error {
	if c == nil {
		return fmt.Errorf("Called Execute() on a nil Command")
	}
	if c.parent == nil { // root Command
		ParseArgs(c, os.Args[1:])
	}
	c.execute()
	return nil

}

func (c *Command) execute() {
	if c.choose == nil {
		for _, v := range c.args {
			if v == "-h" || v == "--help" {
				c.Print_help()
				return
			}
		}
		c.Run(c, c.args)
		return
	}
	c.choose.execute()
}

func ParseArgs(c *Command, args []string) {
	if len(args) < 1 {
		return
	}
	for _, v := range c.commands {
		if v.Use == args[0] { //there is any sub command fit
			c.args = args[:1]
			c.choose = v
			ParseArgs(v, args[1:])
			return
		}
	}
	c.args = args // there is no sub command, then all args belong to current command
	c.PersistentFlags().Parse(c.args)
}

func (c *Command) PersistentFlags() *flag.FlagSet {
	if c.pflags == nil {
		c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	}
	return c.pflags
}

func (c *Command) Name() string {
	name := c.Use
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Print_help() {
	fmt.Printf("%s\n\n", c.Long)
	fmt.Printf("Usage:\n")
	fmt.Printf("\t%s [flags]\n", c.Name())
	if len(c.commands) > 0 {
		fmt.Printf("\t%s [command]\n\n", c.Name())
		fmt.Printf("Available Commands:\n")
		for _, v := range c.commands {
			fmt.Printf("\t%-10s%s\n", v.Name(), v.Short)
		}
	}

	fmt.Printf("\nFlags:\n")

	c.PersistentFlags().VisitAll(func(flag *flag.Flag) {
		fmt.Printf("\t-%1s, --%-6s %-12s%s (default \"%s\")\n", flag.Shorthand, flag.Name, flag.Value.Type(), flag.Usage, flag.DefValue)
	})

	fmt.Printf("\t-%1s, --%-19s%s%s\n", "h", "help", "help for ", c.Name())
	fmt.Println()
	if len(c.commands) > 0 {
		fmt.Printf("Use \"%s [command] --help\" for more information about a command.\n", c.Name())
	}
	fmt.Println()
}
